package com.ones.kit.log.aspect;

import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.ones.kit.log.annotation.OnesLog;
import com.ones.kit.log.constant.OnesLogConsts;
import com.ones.kit.log.model.entity.OnesBizLog;
import com.ones.kit.log.service.OnesLogService;
import com.ones.kit.log.util.OnesLogUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Map;

/**
 * 业务日志Aspect 切面
 * @author Clark
 * @version 2024-09-23
 */
@Slf4j
@Aspect
public class OnesLogAspect {

    @Autowired
    protected OnesLogService logService;

    /**
     * 环绕通知
     */
    @Around("@annotation(onesLog)")
    public Object arround(ProceedingJoinPoint point, OnesLog onesLog) throws Throwable {
        String strClassName = point.getTarget().getClass().getName();
        String strMethodName = point.getSignature().getName();
        log.debug("[类名]:{},[方法]:{}", strClassName, strMethodName);
        // 开始时间
        long startTime = System.currentTimeMillis();
        String serviceName = StrUtil.isNotBlank(onesLog.serviceName()) ? onesLog.serviceName() : null;
        String title = StrUtil.isNotBlank(onesLog.title()) ? onesLog.title() : strClassName + "." + strMethodName;

        OnesBizLog bizLog = OnesLogUtils.getBizLog();
        bizLog.setServiceName(serviceName);
        bizLog.setTitle(title);
        bizLog.setStatus(OnesLogConsts.STATUS_SUCCESS);
        bizLog.setReqContent(getNameAndValue(point));

        try {
            Object result = point.proceed();
            // 正常返回
            bizLog.setResContent(JSONUtil.toJsonStr(result));
            return result;
        } catch (Throwable e) {
            // 异常场合
            bizLog.setStatus(OnesLogConsts.STATUS_FAIL);
            bizLog.setException(ExceptionUtil.stacktraceToString(e));
            throw e;
        } finally {
            // 调用耗时
            bizLog.setTime(System.currentTimeMillis() - startTime);
            // 记录日志
            this.logService.save(bizLog);
        }
    }

    /**
     *  获取方法参数名和参数值
     * @param point
     * @return String
     */
    protected String getNameAndValue(ProceedingJoinPoint point) {
        final Signature signature = point.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        final String[] names = methodSignature.getParameterNames();
        final Object[] args = point.getArgs();

        if (ArrayUtil.isEmpty(names) || ArrayUtil.isEmpty(args)) {
            return StrUtil.EMPTY;
        }
        if (names.length != args.length) {
            log.warn("{}方法参数名和参数值数量不一致", methodSignature.getName());
            return names.toString() + StrUtil.UNDERLINE + args.toString();
        }
        Map<String, Object> map = MapUtil.newHashMap();
        for (int i = 0; i < names.length; i++) {
            map.put(names[i], args[i]);
        }

        return JSONUtil.toJsonStr(map);
    }
}